/**

common test class to use for testing the nonWebSQL drivers if they are able to correctly implement the
evaluation relational expressions (i.e., SELECT commands) and statements (INSERT, UPDATE, DELETE commands).

	crcDB - global variable defined in app/SQL.js
	initDB - function defined in app/SQL.js; simulated in the test case below

*/
RelationalOperationsCommonTest = Class.extend(function(){
	

	var tests = {} //a json object consisting of test cases (i.e., js functions)
	    ,data   = CommonTestData.data();
	
    (console && console.clear());
    
	crcDB = null;
    
	re.apply(tests, {
	
        shortName : 'crcInv1',
        
        version : '1.0',
        
        displayName : 'CRC Database',
        
        maxSize : 1024 * 1024 * 5,
        
        mode : 'sync', //set in synchronous mode for now since test classes is assuming sync. mode. but only localStorage driver will recognise this.
        
		localStorageDriver : "WebSQL",
	   
	    initDB : function(){		         
            
			if( crcDB !== null ) return;

			if( this.localStorageDriver != WebSQLAPICommonTest.WEB_SQL ){
			                
				crcDB = openDatabase2({
					shortName : this.shortName
				   ,dbName : this.shortName
				   ,version : this.version
				   ,displayName : this.displayName
				   ,maxSize  : this.maxSize
				   ,storageDriver : this.localStorageDriver
				   ,mode : this.mode
				});
				
				return;
			}
			
			try {

				if (!window.openDatabase) {
					alert('not supported');
				} else {
					var myDB = openDatabase(this.shortName, this.version, this.displayName, this.maxSize);
					//alert("database created");
				}
			} catch (e) {
				// Error handling code goes here.
				if (e == INVALID_STATE_ERR) {
					// Version number mismatch.
					alert("Invalid database version.");
				} else {
					alert("Unknown error " + e + ".");
				}
				return;
			}
			
			crcDB = myDB;
		
		}
	
		//this function is similar to the ExecuteReader* functions in the app.
		,executeReader : function(query, db, callback, params){

			//params = params || [];
            
            try{
            
                db.transaction(function (transaction) {
                    transaction.executeSql(query, params, function(transaction, result){
                        //console.log(query);
                        callback(transaction, result);
                    }, function (transaction, error) {
                        console.log(error);
                        console.log(query);
                        callback(transaction, error);
                    });
                });
                
            }
            
			catch(e){
            
                callback({}, { code: e.code || '', message: e.message || '' });
                
            }
		}
		
		//gets the data of the SQLResult object
		,srData : function(sqlResult){

			var data = [];			
			
            for(var i = 0, len = sqlResult.rows.length; i < len; i++){
				data = data.concat([sqlResult.rows.item(i)]);
			}

			return data;
			
		}
	
		,isSQLError : function(v){
			return typeof v === 'object' && v.toString() == '[object SQLError]';
		}
		
		,isSQLResultSet : function(v){
			return typeof v === 'object' && v.toString() == '[object SQLResultSet]';
		}
		
        ,currentQueue : null
        
        ,registerOps : function(operations){

            var
            
                currentQueue = this.currentQueue,
                
                _registerOps = function(operations, callbacks){
            
                    var fn = function(op, jsTestCallback, _params){
                        var testCase = this;
                        return function(asyncCallback){
                            testCase.executeReader(op, crcDB, function(){                            
                                jsTestCallback.apply(testCase, arguments);
                                asyncCallback();
                            }, _params);
                        };                        
                    }, _testFns = [], emptyFn = function(){}, i, len, _operation
                    ,_fn, _data, _op, j, jLen, row, key, keys = [], values = [], _op_, _params;
                    
                    for(i = 0, len = operations.length; i < len; i++){
                    
                        _operation = operations[i];
                        _op           = _operation.op;
                        _op_         = _op
                        _data        = _operation.data || [null];
                        _params     = _operation.params;// || [];
						
                        if( !_op ) { 
                            continue; 
                        }
                        
                         for(j = 0, jLen = _data.length; j < jLen; j++){
                            row = _data[j]
                            if( row ){
                                keys = []; values = [];
                                for(key in row){
                                    keys = keys.concat([key]);
                                    values = values.concat([ (typeof row[key] === 'string' ? "'" + row[key].replace(/\'/g, "''") + "'" : row[key]) ]);
                                }                                
                                _op_ = _op.replace("?fields?", keys.join(','))
                                                  .replace("?values?", values.join(','));
                            }                            
                            _fn = _operation.testFn || emptyFn;
                            if( callbacks ){
                                _fn = callbacks ? callbacks.add(_fn) : _fn;
                                _testFns = _testFns.concat([fn.apply(this, [_op_, _fn, _params])]);
                            }
                            else{
                                this.executeReader(_op_, crcDB, _fn, _params);
                            }                         
                         }                         
                    }
                    
                    if( _testFns.length ){
                        async.series(_testFns, function(){});
                    }
                    
                };

            //not an AsyncTest
            if( this.mode === 'sync' || !currentQueue ){                
                _registerOps.apply(this, [operations]); //scoped to the current TestCase class
                return;
            }
            
            currentQueue.call(function(callbacks){
                _registerOps.apply(this, [operations, callbacks]); //scoped to the current TestCase class
            });
            
        }
        
        ,isTestingWebSQL : function(){
        
            return (this.localStorageDriver == WebSQLAPICommonTest.WEB_SQL && typeof window.openDatabase === 'function');
        }
	});
	
    tests.setUp = data.setUp || function(){};
    tests.tearDown = data.tearDown || function(){};
    
    delete data.setUp;
    delete data.tearDown;
    
	if( data["testOnly"] != undefined  ){
		
		var tstOnly = re.isArray(data["testOnly"]) ? data["testOnly"] : [data["testOnly"]];
		var _data = {};
		for(var i = 0, len = tstOnly.length; i < len; i++){
			
			if( data[tstOnly[i]] != undefined ){				
				_data[tstOnly[i]] = data[tstOnly[i]];
			}
			
		}
		
		data   = _data;
		
	}
	
	for(var index in data){	
	
		var _tstParams = data[index];
		
        if( typeof _tstParams === 'function' ){
        
            
            tests[index.toString()] = function(fn){
                return function(queue){
                    this.currentQueue = queue;
                    fn.apply(this, arguments);
                }                
             }.apply(this, [_tstParams]);
            
            continue;

        }
        
		//if( undefined == _tstParams["query"] && undefined == _tstParams.testFn ) continue;
	
		if( undefined != _tstParams.testFn ) {
		
			tests[index.toString()] = function(testParams){
		
				return testParams.testFn;
				
			}.apply(this, [_tstParams]);
			
			continue;
		
		}
		
		if( undefined == _tstParams["query"] ) continue;
		
		tests[index.toString()] = function(testParams){
			
			
			return function(){
				
				if( typeof testParams.preTest == 'function' ){
					testParams.preTest.apply(this, []);
				}
				
				if( typeof testParams.evaluateResult == 'function' ){
					var testIns = this;
					this.executeReader(testParams.query, crcDB, function(t, r_or_e){
						assertTrue(testParams.evaluateResult.apply(testIns, [t, r_or_e, testParams]));
					});
				}
				
				if( typeof testParams.postTest == 'function' ){
					testParams.postTest.apply(this, []);
				}
			}
			
		}.apply(this, [_tstParams]);

	}

	return tests;

}());